package application.anno.impl;

import application.anno.AutoClose;
import application.anno.AutoRegister;
import application.manager.annotationManager.AutoCloseManager;
import application.util.ReflectionsUtil;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class AutoCloseImpl {

    public void unregisterObject(Object o) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        List<Field> fields = Arrays.asList(o.getClass().getDeclaredFields());
        Set<Field> annotationByField = ReflectionsUtil.getAnnotationByField(AutoClose.class);
        if (annotationByField == null) {
            return;
        }
        annotationByField.retainAll(fields);
        for (Field field : annotationByField) {
            Object object = field.get(o);
            AutoClose declaredAnnotation = object.getClass().getDeclaredAnnotation(AutoClose.class);
            declaredAnnotation = declaredAnnotation == null ? object.getClass().getSuperclass().getDeclaredAnnotation(AutoClose.class) : declaredAnnotation;
            if (declaredAnnotation.methodName().isEmpty()) {
                return;
            }
            Method unregister = getMethod(object.getClass(), declaredAnnotation);
            unregister.setAccessible(true);
            unregister.invoke(object);
        }
    }

    public void unregisterListObject() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Map<Class<?>, Object> autoCloses = AutoCloseManager.getInstance().getAutoCloses();
        for (Object o : autoCloses.values()) {
            unregisterObject(o);
        }
    }

    public void unregisterClass(Class<?> cls) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object o = AutoCloseManager.getInstance().getAutoCloses().get(cls);
        AutoClose declaredAnnotation = cls.getDeclaredAnnotation(AutoClose.class);
        declaredAnnotation = declaredAnnotation == null ? cls.getSuperclass().getDeclaredAnnotation(AutoClose.class) : declaredAnnotation;
        if (declaredAnnotation.methodName().isEmpty()) {
            return;
        }
        Method unregister = getMethod(cls, declaredAnnotation);
        unregister.setAccessible(true);
        if (o == null) {
            return;
        }
        unregister.invoke(o);
    }

    public void unregisterListClass() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Set<Class<?>> annotationByClass = ReflectionsUtil.getAnnotationByClass(AutoClose.class, false);
        for (Class<?> cls : annotationByClass) {
            unregisterClass(cls);
        }
    }

    public Method getMethod(Class<?> cls, AutoClose autoClose) throws NoSuchMethodException {
        for (Method method : cls.getDeclaredMethods()) {
            if (autoClose.methodName().equals(method.getName())) {
                return method;
            }
        }
        return cls.getSuperclass().getDeclaredMethod(autoClose.methodName());
    }
}
